feat: add plain-HTTP listeners for various repository configurations to support non-HTTPS access

Signed-off-by: d9pouces <github@19pouces.net>
This commit is contained in:
d9pouces
2026-10-06 22:08:02 +02:00
parent 665eb215bd
commit 8598f323d9
32 changed files with 495 additions and 78 deletions
+23
View File
@@ -7,6 +7,7 @@ the destination directory.
from __future__ import annotations from __future__ import annotations
import re
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from id_configurator.context import Context from id_configurator.context import Context
@@ -49,3 +50,25 @@ def sanitize_filename(name: str) -> str:
create - instead of the single file the caller asked for. create - instead of the single file the caller asked for.
""" """
return name.replace("/", "_").replace("\\", "_") return name.replace("/", "_").replace("\\", "_")
_REPOSITORY_NAME_FORBIDDEN_CHARS = re.compile(r"[^A-Za-z0-9_-]")
def sanitize_repository_name(name: str) -> str:
"""Replace every character of `name` that isn't a plain identifier
character (letters, digits, `_`, `-`) with `_`.
Several modules write a repository's name verbatim as a bare,
unquoted identifier in a generated config file - an INI section
header, a TOML table key, ... - where an unrestricted name could break
out of that syntax (e.g. `]`, a newline, or - for TOML - a literal
`.`, which would silently open extra, nested tables instead of naming
the one table it's meant to). Excluding `.` from the allowed
characters also means the result can never come out as exactly `.` or
`..`, which matter if the name is ever reused as a filesystem path
component (`sanitize_filename` alone wouldn't catch those, since it
only strips `/` and `\\`). Spaces and every other non-identifier
character are replaced the same way, for consistency across callers.
"""
return _REPOSITORY_NAME_FORBIDDEN_CHARS.sub("_", name)
+13 -3
View File
@@ -30,7 +30,10 @@ tool targets Docker images, which are built and run as root:
own bootstrapping and, when combined with the `sbt.override.build.repos` own bootstrapping and, when combined with the `sbt.override.build.repos`
system property, for every project's resolvers as well. system property, for every project's resolvers as well.
- Leiningen: `~/.lein/profiles.clj`, adding the repositories to the `:user` - Leiningen: `~/.lein/profiles.clj`, adding the repositories to the `:user`
profile. profile. Leiningen, alone among these, refuses a plain-HTTP repository
outright ("Tried to use insecure HTTP repository without TLS"); a
repository whose URL isn't HTTPS gets `:insecure true` added to its entry,
Leiningen's own documented escape hatch for this.
""" """
from __future__ import annotations from __future__ import annotations
@@ -39,6 +42,7 @@ import json
import logging import logging
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from pathlib import Path from pathlib import Path
from urllib.parse import urlparse
import jks import jks
from cryptography import x509 from cryptography import x509
@@ -244,10 +248,16 @@ def _write_sbt_repositories(
logger.info("configured sbt to use %d repositories", len(repositories)) logger.info("configured sbt to use %d repositories", len(repositories))
def _lein_repository_entry(repository: JavaRepository) -> str:
options = f":url {_string_literal(repository.url)}"
if urlparse(repository.url).scheme.lower() != "https":
options += " :insecure true"
return f"[{_string_literal(repository.name)} {{{options}}}]"
def _write_lein_profiles(context: Context, repositories: list[JavaRepository]) -> None: def _write_lein_profiles(context: Context, repositories: list[JavaRepository]) -> None:
entries = " ".join( entries = " ".join(
f"[{_string_literal(repository.name)} {{:url {_string_literal(repository.url)}}}]" _lein_repository_entry(repository) for repository in repositories
for repository in repositories
) )
content = f"{{:user {{:repositories [{entries}]}}}}\n" content = f"{{:user {{:repositories [{entries}]}}}}\n"
context.write_file(_LEIN_PROFILES, content.encode("utf-8")) context.write_file(_LEIN_PROFILES, content.encode("utf-8"))
+2 -16
View File
@@ -25,12 +25,11 @@ from __future__ import annotations
import json import json
import logging import logging
import re
from urllib.parse import urlparse from urllib.parse import urlparse
from id_configurator.config import PythonRepository from id_configurator.config import PythonRepository
from id_configurator.context import Context from id_configurator.context import Context
from id_configurator.modules.base import Module, register from id_configurator.modules.base import Module, register, sanitize_repository_name
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -39,25 +38,12 @@ _PIP_CONF = "etc/pip.conf"
_UV_TOML = "etc/uv/uv.toml" _UV_TOML = "etc/uv/uv.toml"
_POETRY_CONFIG = "root/.config/pypoetry/config.toml" _POETRY_CONFIG = "root/.config/pypoetry/config.toml"
_DISTUTILS_GLOBS = ("usr/lib/python3.*", "usr/local/lib/python3.*") _DISTUTILS_GLOBS = ("usr/lib/python3.*", "usr/local/lib/python3.*")
_REPOSITORY_NAME_FORBIDDEN_CHARS = re.compile(r"[^A-Za-z0-9_-]")
def _toml_string(value: str) -> str: def _toml_string(value: str) -> str:
return json.dumps(value) return json.dumps(value)
def _sanitize_repository_name(name: str) -> str:
"""Replace every character of `name` that isn't a plain identifier
character with `_`.
`name` is written verbatim as a TOML table key (`[repositories.name]`,
`[certificates.name]`) in poetry's config: an unrestricted name could
break out of the table header, or (via a literal `.`) silently create
extra, nested tables instead of naming the one table it is meant to.
"""
return _REPOSITORY_NAME_FORBIDDEN_CHARS.sub("_", name)
def _trusted_host(repository: PythonRepository) -> str | None: def _trusted_host(repository: PythonRepository) -> str | None:
parsed = urlparse(repository.index_url) parsed = urlparse(repository.index_url)
return None if parsed.scheme.lower() == "https" else parsed.hostname return None if parsed.scheme.lower() == "https" else parsed.hostname
@@ -97,7 +83,7 @@ def _write_poetry_config(
) -> None: ) -> None:
lines = [] lines = []
for repository in repositories: for repository in repositories:
name = _sanitize_repository_name(repository.name) name = sanitize_repository_name(repository.name)
lines.append(f"[repositories.{name}]") lines.append(f"[repositories.{name}]")
lines.append(f"url = {_toml_string(repository.index_url)}") lines.append(f"url = {_toml_string(repository.index_url)}")
lines.append("") lines.append("")
+3 -18
View File
@@ -29,29 +29,14 @@ which this module otherwise has no visibility into.
from __future__ import annotations from __future__ import annotations
import logging import logging
import re
from id_configurator.config import RustRepository from id_configurator.config import RustRepository
from id_configurator.context import Context from id_configurator.context import Context
from id_configurator.modules.base import Module, register from id_configurator.modules.base import Module, register, sanitize_repository_name
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
_CARGO_CONFIG = ".cargo/config.toml" _CARGO_CONFIG = ".cargo/config.toml"
_REPOSITORY_NAME_FORBIDDEN_CHARS = re.compile(r"[^A-Za-z0-9_-]")
def _sanitize_repository_name(name: str) -> str:
"""Replace every character of `name` that isn't a plain identifier
character with `_`.
`name` is written verbatim both as a TOML table key (`[source.name]`,
`[registries.name]`) and inside a quoted string (`replace-with =
"name"`): an unrestricted name could break out of the table header or
string, or (via a literal `.`) silently create extra, nested tables
instead of naming the one table it is meant to.
"""
return _REPOSITORY_NAME_FORBIDDEN_CHARS.sub("_", name)
def _index_url(repository: RustRepository) -> str: def _index_url(repository: RustRepository) -> str:
@@ -60,7 +45,7 @@ def _index_url(repository: RustRepository) -> str:
def _write_cargo_config(context: Context, repositories: list[RustRepository]) -> None: def _write_cargo_config(context: Context, repositories: list[RustRepository]) -> None:
primary = repositories[0] primary = repositories[0]
primary_name = _sanitize_repository_name(primary.name) primary_name = sanitize_repository_name(primary.name)
lines = [ lines = [
"[source.crates-io]", "[source.crates-io]",
f'replace-with = "{primary_name}"', f'replace-with = "{primary_name}"',
@@ -69,7 +54,7 @@ def _write_cargo_config(context: Context, repositories: list[RustRepository]) ->
f'registry = "{_index_url(primary)}"', f'registry = "{_index_url(primary)}"',
] ]
for repository in repositories[1:]: for repository in repositories[1:]:
name = _sanitize_repository_name(repository.name) name = sanitize_repository_name(repository.name)
lines += [ lines += [
"", "",
f"[registries.{name}]", f"[registries.{name}]",
+7 -16
View File
@@ -32,7 +32,6 @@ from __future__ import annotations
import configparser import configparser
import fnmatch import fnmatch
import logging import logging
import re
import shutil import shutil
import subprocess import subprocess
import tempfile import tempfile
@@ -41,25 +40,17 @@ from io import StringIO
from id_configurator.config import NamedContent, YumRepository from id_configurator.config import NamedContent, YumRepository
from id_configurator.context import Context from id_configurator.context import Context
from id_configurator.modules.base import Module, register, sanitize_filename from id_configurator.modules.base import (
Module,
register,
sanitize_filename,
sanitize_repository_name,
)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
_REPOS_DIR = "etc/yum.repos.d" _REPOS_DIR = "etc/yum.repos.d"
_RPM_GPG_DIR = "etc/pki/rpm-gpg" _RPM_GPG_DIR = "etc/pki/rpm-gpg"
_REPOSITORY_NAME_FORBIDDEN_CHARS = re.compile(r"[^A-Za-z0-9._-]")
def _sanitize_repository_name(name: str) -> str:
"""Replace every character of `name` that isn't a plain identifier
character with `_`.
`name` is written verbatim as the `.repo` file's INI section header
(`[name]`): an unrestricted name (containing `]`, a newline, ...) could
otherwise inject extra, attacker-controlled sections into the file
instead of just naming the one section it is meant to.
"""
return _REPOSITORY_NAME_FORBIDDEN_CHARS.sub("_", name)
def _disable_repo_content(content: str, patterns: Sequence[str]) -> str: def _disable_repo_content(content: str, patterns: Sequence[str]) -> str:
@@ -105,7 +96,7 @@ def _disable_existing_repos(context: Context, patterns: Sequence[str]) -> None:
def _write_repo_file(context: Context, repository: YumRepository) -> None: def _write_repo_file(context: Context, repository: YumRepository) -> None:
name = _sanitize_repository_name(repository.name) name = sanitize_repository_name(repository.name)
lines = [ lines = [
f"[{name}]", f"[{name}]",
f"name={name}", f"name={name}",
+2 -1
View File
@@ -11,7 +11,8 @@ configurations:
apk: apk:
repositories: repositories:
- name: demo - name: demo
url: https://host.docker.internal:{{ 'APK_REPO_PORT' | env }}/ {% set scheme = 'APK_REPO_SCHEME' | env %}
url: {{ scheme }}://host.docker.internal:{{ ('APK_REPO_PORT' if scheme == 'https' else 'APK_REPO_HTTP_PORT') | env }}/
url_to_replace: https://dl-cdn.alpinelinux.org/* url_to_replace: https://dl-cdn.alpinelinux.org/*
key: | key: |
{{ 'dockerfiles/repos/040d0af5f97a0a44.rsa.pub' | file | indent(8, first=true) }} {{ 'dockerfiles/repos/040d0af5f97a0a44.rsa.pub' | file | indent(8, first=true) }}
+2 -1
View File
@@ -11,7 +11,8 @@ configurations:
- name: demo - name: demo
types: [deb] types: [deb]
uris: uris:
- https://host.docker.internal:{{ 'APT_REPO_PORT' | env }}/ {% set scheme = 'APT_REPO_SCHEME' | env %}
- {{ scheme }}://host.docker.internal:{{ ('APT_REPO_PORT' if scheme == 'https' else 'APT_REPO_HTTP_PORT') | env }}/
suites: ["./"] suites: ["./"]
uri-to-replace: http://deb.debian.org/* uri-to-replace: http://deb.debian.org/*
signed-by: | signed-by: |
+2 -1
View File
@@ -26,7 +26,8 @@ configurations:
go: go:
repositories: repositories:
- name: demo - name: demo
url: https://host.docker.internal:{{ 'GO_REPO_PORT' | env }}/ {% set scheme = 'GO_REPO_SCHEME' | env %}
url: {{ scheme }}://host.docker.internal:{{ ('GO_REPO_PORT' if scheme == 'https' else 'GO_REPO_HTTP_PORT') | env }}/
ruby: ruby:
repositories: [] repositories: []
nuget: nuget:
+2 -1
View File
@@ -23,7 +23,8 @@ configurations:
# during the Dockerfile's warm-up step. All other tools just see it as # during the Dockerfile's warm-up step. All other tools just see it as
# an ordinary repository, and find the test artifact here. # an ordinary repository, and find the test artifact here.
- name: central - name: central
url: https://host.docker.internal:{{ 'JAVA_REPO_PORT' | env }}/ {% set scheme = 'JAVA_REPO_SCHEME' | env %}
url: {{ scheme }}://host.docker.internal:{{ ('JAVA_REPO_PORT' if scheme == 'https' else 'JAVA_REPO_HTTP_PORT') | env }}/
# Second entry: only SBT needs this. With # Second entry: only SBT needs this. With
# -Dsbt.override.build.repos=true (the only way SBT actually consults # -Dsbt.override.build.repos=true (the only way SBT actually consults
# this file for project dependencies, not just its own bootstrap), the # this file for project dependencies, not just its own bootstrap), the
+2 -1
View File
@@ -22,7 +22,8 @@ configurations:
npm: npm:
repositories: repositories:
- name: demo - name: demo
url: https://host.docker.internal:{{ 'NPM_REPO_PORT' | env }}/ {% set scheme = 'NPM_REPO_SCHEME' | env %}
url: {{ scheme }}://host.docker.internal:{{ ('NPM_REPO_PORT' if scheme == 'https' else 'NPM_REPO_HTTP_PORT') | env }}/
rust: rust:
repositories: [] repositories: []
go: go:
+2 -1
View File
@@ -30,4 +30,5 @@ configurations:
nuget: nuget:
repositories: repositories:
- name: demo - name: demo
url: https://host.docker.internal:{{ 'NUGET_REPO_PORT' | env }}/index.json {% set scheme = 'NUGET_REPO_SCHEME' | env %}
url: {{ scheme }}://host.docker.internal:{{ ('NUGET_REPO_PORT' if scheme == 'https' else 'NUGET_REPO_HTTP_PORT') | env }}/index.json
+2 -1
View File
@@ -20,7 +20,8 @@ configurations:
php: php:
repositories: repositories:
- name: demo - name: demo
url: https://host.docker.internal:{{ 'PHP_REPO_PORT' | env }}/ {% set scheme = 'PHP_REPO_SCHEME' | env %}
url: {{ scheme }}://host.docker.internal:{{ ('PHP_REPO_PORT' if scheme == 'https' else 'PHP_REPO_HTTP_PORT') | env }}/
npm: npm:
repositories: [] repositories: []
rust: rust:
+2 -1
View File
@@ -16,7 +16,8 @@ configurations:
python: python:
repositories: repositories:
- name: demo - name: demo
index-url: https://host.docker.internal:{{ 'PYPI_REPO_PORT' | env }}/simple/ {% set scheme = 'PYPI_REPO_SCHEME' | env %}
index-url: {{ scheme }}://host.docker.internal:{{ ('PYPI_REPO_PORT' if scheme == 'https' else 'PYPI_REPO_HTTP_PORT') | env }}/simple/
java: java:
repositories: [] repositories: []
php: php:
+2 -1
View File
@@ -28,6 +28,7 @@ configurations:
ruby: ruby:
repositories: repositories:
- name: demo - name: demo
url: https://host.docker.internal:{{ 'RUBY_REPO_PORT' | env }}/ {% set scheme = 'RUBY_REPO_SCHEME' | env %}
url: {{ scheme }}://host.docker.internal:{{ ('RUBY_REPO_PORT' if scheme == 'https' else 'RUBY_REPO_HTTP_PORT') | env }}/
nuget: nuget:
repositories: [] repositories: []
+2 -1
View File
@@ -24,7 +24,8 @@ configurations:
rust: rust:
repositories: repositories:
- name: demo - name: demo
url: https://host.docker.internal:{{ 'CARGO_REPO_PORT' | env }}/ {% set scheme = 'CARGO_REPO_SCHEME' | env %}
url: {{ scheme }}://host.docker.internal:{{ ('CARGO_REPO_PORT' if scheme == 'https' else 'CARGO_REPO_HTTP_PORT') | env }}/
is_sparse: true is_sparse: true
go: go:
repositories: [] repositories: []
+2 -1
View File
@@ -13,7 +13,8 @@ configurations:
yum: yum:
repositories: repositories:
- name: demo - name: demo
index-url: https://host.docker.internal:{{ 'YUM_REPO_PORT' | env }}/ {% set scheme = 'YUM_REPO_SCHEME' | env %}
index-url: {{ scheme }}://host.docker.internal:{{ ('YUM_REPO_PORT' if scheme == 'https' else 'YUM_REPO_HTTP_PORT') | env }}/
index-url-to-replace: https://mirrors.rockylinux.org/* index-url-to-replace: https://mirrors.rockylinux.org/*
keys: [] keys: []
python: python:
+2 -1
View File
@@ -5,6 +5,7 @@ COPY --from=generated-config Python.yaml /config.yaml
RUN id-configurator apply --config /config.yaml --src /src --dst /dst RUN id-configurator apply --config /config.yaml --src /src --dst /dst
FROM target AS runtime FROM target AS runtime
ARG PYPI_REPO_PORT ARG PYPI_REPO_PORT
ARG PYPI_REPO_SCHEME
# Warm up uv and poetry themselves from the real, network-reachable PyPI # Warm up uv and poetry themselves from the real, network-reachable PyPI
# while the default index is still in place, so the actual tests below # while the default index is still in place, so the actual tests below
# never need anything but the fixture repository configured by # never need anything but the fixture repository configured by
@@ -20,5 +21,5 @@ RUN uv pip install --system idconfiguratortestpkg \
&& python3 -c "import idconfiguratortestpkg" && python3 -c "import idconfiguratortestpkg"
RUN mkdir -p /tmp/poetrytest && cd /tmp/poetrytest \ RUN mkdir -p /tmp/poetrytest && cd /tmp/poetrytest \
&& poetry init -n --name poetrytest \ && poetry init -n --name poetrytest \
&& poetry source add --priority explicit demo "https://host.docker.internal:${PYPI_REPO_PORT}/simple/" \ && poetry source add --priority explicit demo "${PYPI_REPO_SCHEME}://host.docker.internal:${PYPI_REPO_PORT}/simple/" \
&& poetry add idconfiguratortestpkg --source demo && poetry add idconfiguratortestpkg --source demo
+2 -1
View File
@@ -5,6 +5,7 @@ COPY --from=generated-config Python.yaml /config.yaml
RUN id-configurator apply --config /config.yaml --src /src --dst /dst RUN id-configurator apply --config /config.yaml --src /src --dst /dst
FROM target AS runtime FROM target AS runtime
ARG PYPI_REPO_PORT ARG PYPI_REPO_PORT
ARG PYPI_REPO_SCHEME
# Warm up uv and poetry themselves from the real, network-reachable PyPI # Warm up uv and poetry themselves from the real, network-reachable PyPI
# while the default index is still in place, so the actual tests below # while the default index is still in place, so the actual tests below
# never need anything but the fixture repository configured by # never need anything but the fixture repository configured by
@@ -20,5 +21,5 @@ RUN uv pip install --system idconfiguratortestpkg \
&& python3 -c "import idconfiguratortestpkg" && python3 -c "import idconfiguratortestpkg"
RUN mkdir -p /tmp/poetrytest && cd /tmp/poetrytest \ RUN mkdir -p /tmp/poetrytest && cd /tmp/poetrytest \
&& poetry init -n --name poetrytest \ && poetry init -n --name poetrytest \
&& poetry source add --priority explicit demo "https://host.docker.internal:${PYPI_REPO_PORT}/simple/" \ && poetry source add --priority explicit demo "${PYPI_REPO_SCHEME}://host.docker.internal:${PYPI_REPO_PORT}/simple/" \
&& poetry add idconfiguratortestpkg --source demo && poetry add idconfiguratortestpkg --source demo
@@ -8,3 +8,13 @@ server {
root /srv; root /srv;
autoindex off; autoindex off;
} }
# Plain-HTTP listener, for the module-*-http tox envs that verify id-configurator
# correctly configures a non-HTTPS repository.
server {
listen 8080 default_server;
server_name _;
root /srv;
autoindex off;
}
@@ -8,3 +8,13 @@ server {
root /srv; root /srv;
autoindex off; autoindex off;
} }
# Plain-HTTP listener, for the module-*-http tox envs that verify id-configurator
# correctly configures a non-HTTPS repository.
server {
listen 8080 default_server;
server_name _;
root /srv;
autoindex off;
}
+20 -2
View File
@@ -12,10 +12,28 @@ server {
# templates, since the host:port this fixture is actually reached on is # templates, since the host:port this fixture is actually reached on is
# only known once tox-docker starts the container, not at image-build # only known once tox-docker starts the container, not at image-build
# time. $http_host reflects exactly what the client (cargo) used to # time. $http_host reflects exactly what the client (cargo) used to
# connect, e.g. host.docker.internal:55123. # connect, e.g. host.docker.internal:55123; $scheme likewise reflects
# whichever of this file's two listeners actually served the request.
location = /config.json { location = /config.json {
default_type application/json; default_type application/json;
sub_filter '__BASE_URL__' 'https://$http_host'; sub_filter '__BASE_URL__' '$scheme://$http_host';
sub_filter_once off;
sub_filter_types application/json;
}
}
# Plain-HTTP listener, for the module-rust-http tox env that verifies
# id-configurator correctly configures a non-HTTPS repository.
server {
listen 8080 default_server;
server_name _;
root /srv;
autoindex off;
location = /config.json {
default_type application/json;
sub_filter '__BASE_URL__' '$scheme://$http_host';
sub_filter_once off; sub_filter_once off;
sub_filter_types application/json; sub_filter_types application/json;
} }
@@ -8,3 +8,13 @@ server {
root /srv; root /srv;
autoindex off; autoindex off;
} }
# Plain-HTTP listener, for the module-*-http tox envs that verify id-configurator
# correctly configures a non-HTTPS repository.
server {
listen 8080 default_server;
server_name _;
root /srv;
autoindex off;
}
@@ -8,3 +8,13 @@ server {
root /srv; root /srv;
autoindex off; autoindex off;
} }
# Plain-HTTP listener, for the module-*-http tox envs that verify id-configurator
# correctly configures a non-HTTPS repository.
server {
listen 8080 default_server;
server_name _;
root /srv;
autoindex off;
}
+21 -2
View File
@@ -12,10 +12,29 @@ server {
# its tarball URL, since the host:port this fixture is actually reached # its tarball URL, since the host:port this fixture is actually reached
# on is only known once tox-docker starts the container, not at # on is only known once tox-docker starts the container, not at
# image-build time. $http_host reflects exactly what the client (npm) # image-build time. $http_host reflects exactly what the client (npm)
# used to connect, e.g. host.docker.internal:55123. # used to connect, e.g. host.docker.internal:55123; $scheme likewise
# reflects whichever of this file's two listeners actually served the
# request.
location = /idconfiguratortestpkg { location = /idconfiguratortestpkg {
default_type application/json; default_type application/json;
sub_filter '__BASE_URL__' 'https://$http_host'; sub_filter '__BASE_URL__' '$scheme://$http_host';
sub_filter_once off;
sub_filter_types application/json;
}
}
# Plain-HTTP listener, for the module-npm-http tox env that verifies
# id-configurator correctly configures a non-HTTPS repository.
server {
listen 8080 default_server;
server_name _;
root /srv;
autoindex off;
location = /idconfiguratortestpkg {
default_type application/json;
sub_filter '__BASE_URL__' '$scheme://$http_host';
sub_filter_once off; sub_filter_once off;
sub_filter_types application/json; sub_filter_types application/json;
} }
+20 -2
View File
@@ -12,10 +12,28 @@ server {
# fields, since the host:port this fixture is actually reached on is # fields, since the host:port this fixture is actually reached on is
# only known once tox-docker starts the container, not at image-build # only known once tox-docker starts the container, not at image-build
# time. $http_host reflects exactly what the client (nuget) used to # time. $http_host reflects exactly what the client (nuget) used to
# connect, e.g. host.docker.internal:55123. # connect, e.g. host.docker.internal:55123; $scheme likewise reflects
# whichever of this file's two listeners actually served the request.
location = /index.json { location = /index.json {
default_type application/json; default_type application/json;
sub_filter '__BASE_URL__' 'https://$http_host'; sub_filter '__BASE_URL__' '$scheme://$http_host';
sub_filter_once off;
sub_filter_types application/json;
}
}
# Plain-HTTP listener, for the module-nuget-http tox env that verifies
# id-configurator correctly configures a non-HTTPS repository.
server {
listen 8080 default_server;
server_name _;
root /srv;
autoindex off;
location = /index.json {
default_type application/json;
sub_filter '__BASE_URL__' '$scheme://$http_host';
sub_filter_once off; sub_filter_once off;
sub_filter_types application/json; sub_filter_types application/json;
} }
+20 -2
View File
@@ -12,10 +12,28 @@ server {
# since the host:port this fixture is actually reached on is only known # since the host:port this fixture is actually reached on is only known
# once tox-docker starts the container, not at image-build time. # once tox-docker starts the container, not at image-build time.
# $http_host reflects exactly what the client (Composer) used to # $http_host reflects exactly what the client (Composer) used to
# connect, e.g. host.docker.internal:55123. # connect, e.g. host.docker.internal:55123; $scheme likewise reflects
# whichever of this file's two listeners actually served the request.
location = /packages.json { location = /packages.json {
default_type application/json; default_type application/json;
sub_filter '__BASE_URL__' 'https://$http_host'; sub_filter '__BASE_URL__' '$scheme://$http_host';
sub_filter_once off;
sub_filter_types application/json;
}
}
# Plain-HTTP listener, for the module-php-http tox env that verifies
# id-configurator correctly configures a non-HTTPS repository.
server {
listen 8080 default_server;
server_name _;
root /srv;
autoindex off;
location = /packages.json {
default_type application/json;
sub_filter '__BASE_URL__' '$scheme://$http_host';
sub_filter_once off; sub_filter_once off;
sub_filter_types application/json; sub_filter_types application/json;
} }
@@ -8,3 +8,13 @@ server {
root /srv; root /srv;
autoindex off; autoindex off;
} }
# Plain-HTTP listener, for the module-*-http tox envs that verify id-configurator
# correctly configures a non-HTTPS repository.
server {
listen 8080 default_server;
server_name _;
root /srv;
autoindex off;
}
@@ -8,3 +8,13 @@ server {
root /srv; root /srv;
autoindex off; autoindex off;
} }
# Plain-HTTP listener, for the module-*-http tox envs that verify id-configurator
# correctly configures a non-HTTPS repository.
server {
listen 8080 default_server;
server_name _;
root /srv;
autoindex off;
}
@@ -8,3 +8,13 @@ server {
root /srv; root /srv;
autoindex off; autoindex off;
} }
# Plain-HTTP listener, for the module-*-http tox envs that verify id-configurator
# correctly configures a non-HTTPS repository.
server {
listen 8080 default_server;
server_name _;
root /srv;
autoindex off;
}
+24
View File
@@ -353,6 +353,30 @@ def test_apply_writes_lein_profiles(tmp_path) -> None:
) )
def test_apply_marks_non_https_lein_repository_as_insecure(tmp_path) -> None:
data = {
"uuid": "12345678-1234-5678-1234-567812345678",
"organisation": "InterDiode",
"configurations": {
"java": {
"repositories": [
{"name": "interdiode", "url": "http://example.invalid/maven"}
]
}
},
}
dst = tmp_path / "dst"
context = Context(config=make_config(data), dst=dst, src=None)
JavaModule().apply(context)
profiles = (dst / "root/.lein/profiles.clj").read_text(encoding="utf-8")
assert profiles == (
"{:user {:repositories "
'[["interdiode" {:url "http://example.invalid/maven" :insecure true}]]}}\n'
)
def test_apply_with_certificates_and_repositories_writes_both(tmp_path) -> None: def test_apply_with_certificates_and_repositories_writes_both(tmp_path) -> None:
src = tmp_path / "src" src = tmp_path / "src"
(src / "usr/lib/jvm/java-21/lib/security").mkdir(parents=True) (src / "usr/lib/jvm/java-21/lib/security").mkdir(parents=True)
+245 -3
View File
@@ -1,5 +1,5 @@
[tox] [tox]
env_list = py313,py314,coverage,packaging,packaging-amd64,packaging-arm64,publish,module-python,module-apt,module-yum,module-apk,module-java,module-certificates,module-php,module-npm,module-rust,module-go,module-ruby,module-nuget,config-url env_list = py313,py314,coverage,packaging,packaging-amd64,packaging-arm64,publish,module-python,module-python-http,module-apt,module-apt-http,module-yum,module-yum-http,module-apk,module-apk-http,module-java,module-java-http,module-certificates,module-php,module-php-http,module-npm,module-npm-http,module-rust,module-rust-http,module-go,module-go-http,module-ruby,module-ruby-http,module-nuget,module-nuget-http,config-url
isolated_build = true isolated_build = true
requires = requires =
tox>=4 tox>=4
@@ -91,6 +91,7 @@ passenv =
dockerfile = {tox_root}/tests/dockerfiles/repos/pypi-repo.Dockerfile dockerfile = {tox_root}/tests/dockerfiles/repos/pypi-repo.Dockerfile
expose = expose =
PYPI_REPO_PORT=8443/tcp PYPI_REPO_PORT=8443/tcp
PYPI_REPO_HTTP_PORT=8080/tcp
healthcheck_cmd = wget --no-check-certificate -qO- https://127.0.0.1:8443/simple/idconfiguratortestpkg/ || exit 1 healthcheck_cmd = wget --no-check-certificate -qO- https://127.0.0.1:8443/simple/idconfiguratortestpkg/ || exit 1
healthcheck_interval = 1 healthcheck_interval = 1
healthcheck_retries = 30 healthcheck_retries = 30
@@ -106,17 +107,41 @@ docker =
pypi-repo pypi-repo
allowlist_externals = allowlist_externals =
docker docker
set_env =
PYPI_REPO_SCHEME = https
commands = commands =
python3 -m id_tools test render-config {tox_root}/tests/configs/Python.yaml.j2 {env_dir}/configs/Python.yaml python3 -m id_tools test render-config {tox_root}/tests/configs/Python.yaml.j2 {env_dir}/configs/Python.yaml
docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-arg PYPI_REPO_PORT={env:PYPI_REPO_PORT} --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Python-alpine.Dockerfile -t id-configurator-python . docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-arg PYPI_REPO_SCHEME={env:PYPI_REPO_SCHEME} --build-arg PYPI_REPO_PORT={env:PYPI_REPO_PORT} --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Python-alpine.Dockerfile -t id-configurator-python .
docker rmi id-configurator-python docker rmi id-configurator-python
docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-arg PYPI_REPO_PORT={env:PYPI_REPO_PORT} --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Python.Dockerfile -t id-configurator-python . docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-arg PYPI_REPO_SCHEME={env:PYPI_REPO_SCHEME} --build-arg PYPI_REPO_PORT={env:PYPI_REPO_PORT} --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Python.Dockerfile -t id-configurator-python .
docker rmi id-configurator-python docker rmi id-configurator-python
[testenv:module-python-http]
package = skip
labels = end-to-end
change_dir = {tox_root}
dependency_groups = dev
docker =
pypi-repo
allowlist_externals =
docker
description =
Same as module-python, but against a plain-HTTP index, to verify pip's
trusted-host is configured correctly for a non-HTTPS repository.
set_env =
PYPI_REPO_SCHEME = http
commands =
python3 -m id_tools test render-config {tox_root}/tests/configs/Python.yaml.j2 {env_dir}/configs/Python.yaml
docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-arg PYPI_REPO_SCHEME={env:PYPI_REPO_SCHEME} --build-arg PYPI_REPO_PORT={env:PYPI_REPO_HTTP_PORT} --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Python-alpine.Dockerfile -t id-configurator-python-http .
docker rmi id-configurator-python-http
docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-arg PYPI_REPO_SCHEME={env:PYPI_REPO_SCHEME} --build-arg PYPI_REPO_PORT={env:PYPI_REPO_HTTP_PORT} --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Python.Dockerfile -t id-configurator-python-http .
docker rmi id-configurator-python-http
[docker:apt-repo] [docker:apt-repo]
dockerfile = {tox_root}/tests/dockerfiles/repos/apt-repo.Dockerfile dockerfile = {tox_root}/tests/dockerfiles/repos/apt-repo.Dockerfile
expose = expose =
APT_REPO_PORT=8443/tcp APT_REPO_PORT=8443/tcp
APT_REPO_HTTP_PORT=8080/tcp
healthcheck_cmd = wget --no-check-certificate -qO- https://127.0.0.1:8443/Packages || exit 1 healthcheck_cmd = wget --no-check-certificate -qO- https://127.0.0.1:8443/Packages || exit 1
healthcheck_interval = 1 healthcheck_interval = 1
healthcheck_retries = 30 healthcheck_retries = 30
@@ -132,15 +157,37 @@ docker =
apt-repo apt-repo
allowlist_externals = allowlist_externals =
docker docker
set_env =
APT_REPO_SCHEME = https
commands = commands =
python3 -m id_tools test render-config {tox_root}/tests/configs/Apt.yaml.j2 {env_dir}/configs/Apt.yaml python3 -m id_tools test render-config {tox_root}/tests/configs/Apt.yaml.j2 {env_dir}/configs/Apt.yaml
docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Apt.Dockerfile -t id-configurator-apt . docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Apt.Dockerfile -t id-configurator-apt .
docker rmi id-configurator-apt docker rmi id-configurator-apt
[testenv:module-apt-http]
package = skip
labels = end-to-end
change_dir = {tox_root}
dependency_groups = dev
docker =
apt-repo
allowlist_externals =
docker
description =
Same as module-apt, but against a plain-HTTP source, since apt's trust
model is the signed-by keyring, independent of transport scheme.
set_env =
APT_REPO_SCHEME = http
commands =
python3 -m id_tools test render-config {tox_root}/tests/configs/Apt.yaml.j2 {env_dir}/configs/Apt.yaml
docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Apt.Dockerfile -t id-configurator-apt-http .
docker rmi id-configurator-apt-http
[docker:yum-repo] [docker:yum-repo]
dockerfile = {tox_root}/tests/dockerfiles/repos/yum-repo.Dockerfile dockerfile = {tox_root}/tests/dockerfiles/repos/yum-repo.Dockerfile
expose = expose =
YUM_REPO_PORT=8443/tcp YUM_REPO_PORT=8443/tcp
YUM_REPO_HTTP_PORT=8080/tcp
healthcheck_cmd = wget --no-check-certificate -qO- https://127.0.0.1:8443/repodata/repomd.xml || exit 1 healthcheck_cmd = wget --no-check-certificate -qO- https://127.0.0.1:8443/repodata/repomd.xml || exit 1
healthcheck_interval = 1 healthcheck_interval = 1
healthcheck_retries = 30 healthcheck_retries = 30
@@ -156,15 +203,37 @@ docker =
yum-repo yum-repo
allowlist_externals = allowlist_externals =
docker docker
set_env =
YUM_REPO_SCHEME = https
commands = commands =
python3 -m id_tools test render-config {tox_root}/tests/configs/Yum.yaml.j2 {env_dir}/configs/Yum.yaml python3 -m id_tools test render-config {tox_root}/tests/configs/Yum.yaml.j2 {env_dir}/configs/Yum.yaml
docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Yum.Dockerfile -t id-configurator-yum . docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Yum.Dockerfile -t id-configurator-yum .
docker rmi id-configurator-yum docker rmi id-configurator-yum
[testenv:module-yum-http]
package = skip
labels = end-to-end
change_dir = {tox_root}
dependency_groups = dev
docker =
yum-repo
allowlist_externals =
docker
description =
Same as module-yum, but against a plain-HTTP repository, since yum/dnf's
trust model is the imported GPG key, independent of transport scheme.
set_env =
YUM_REPO_SCHEME = http
commands =
python3 -m id_tools test render-config {tox_root}/tests/configs/Yum.yaml.j2 {env_dir}/configs/Yum.yaml
docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Yum.Dockerfile -t id-configurator-yum-http .
docker rmi id-configurator-yum-http
[docker:apk-repo] [docker:apk-repo]
dockerfile = {tox_root}/tests/dockerfiles/repos/apk-repo.Dockerfile dockerfile = {tox_root}/tests/dockerfiles/repos/apk-repo.Dockerfile
expose = expose =
APK_REPO_PORT=8443/tcp APK_REPO_PORT=8443/tcp
APK_REPO_HTTP_PORT=8080/tcp
healthcheck_cmd = wget --no-check-certificate -qO- https://127.0.0.1:8443/APKINDEX.tar.gz || exit 1 healthcheck_cmd = wget --no-check-certificate -qO- https://127.0.0.1:8443/APKINDEX.tar.gz || exit 1
healthcheck_interval = 1 healthcheck_interval = 1
healthcheck_retries = 30 healthcheck_retries = 30
@@ -189,15 +258,39 @@ description =
native platform keeps them in agreement everywhere (including under native platform keeps them in agreement everywhere (including under
QEMU emulation on non-amd64 hosts); CI runners are amd64, so this still QEMU emulation on non-amd64 hosts); CI runners are amd64, so this still
matches the other envs there. matches the other envs there.
set_env =
APK_REPO_SCHEME = https
commands = commands =
python3 -m id_tools test render-config {tox_root}/tests/configs/Apk.yaml.j2 {env_dir}/configs/Apk.yaml python3 -m id_tools test render-config {tox_root}/tests/configs/Apk.yaml.j2 {env_dir}/configs/Apk.yaml
docker buildx build --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Apk.Dockerfile -t id-configurator-apk . docker buildx build --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Apk.Dockerfile -t id-configurator-apk .
docker rmi id-configurator-apk docker rmi id-configurator-apk
[testenv:module-apk-http]
package = skip
labels = end-to-end
change_dir = {tox_root}
dependency_groups = dev
docker =
apk-repo
allowlist_externals =
docker
description =
Same as module-apk, but against a plain-HTTP repository, since apk's
trust model is the signed index, independent of transport scheme. See
module-apk's own description for why this isn't pinned to --platform
linux/amd64 either.
set_env =
APK_REPO_SCHEME = http
commands =
python3 -m id_tools test render-config {tox_root}/tests/configs/Apk.yaml.j2 {env_dir}/configs/Apk.yaml
docker buildx build --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Apk.Dockerfile -t id-configurator-apk-http .
docker rmi id-configurator-apk-http
[docker:java-repo] [docker:java-repo]
dockerfile = {tox_root}/tests/dockerfiles/repos/java-repo.Dockerfile dockerfile = {tox_root}/tests/dockerfiles/repos/java-repo.Dockerfile
expose = expose =
JAVA_REPO_PORT=8443/tcp JAVA_REPO_PORT=8443/tcp
JAVA_REPO_HTTP_PORT=8080/tcp
healthcheck_cmd = wget --no-check-certificate -qO- https://127.0.0.1:8443/org/interdiode/idconfiguratortestpkg/0.0.1/idconfiguratortestpkg-0.0.1.pom || exit 1 healthcheck_cmd = wget --no-check-certificate -qO- https://127.0.0.1:8443/org/interdiode/idconfiguratortestpkg/0.0.1/idconfiguratortestpkg-0.0.1.pom || exit 1
healthcheck_interval = 1 healthcheck_interval = 1
healthcheck_retries = 30 healthcheck_retries = 30
@@ -213,11 +306,31 @@ docker =
java-repo java-repo
allowlist_externals = allowlist_externals =
docker docker
set_env =
JAVA_REPO_SCHEME = https
commands = commands =
python3 -m id_tools test render-config {tox_root}/tests/configs/Java.yaml.j2 {env_dir}/configs/Java.yaml python3 -m id_tools test render-config {tox_root}/tests/configs/Java.yaml.j2 {env_dir}/configs/Java.yaml
docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Java.Dockerfile -t id-configurator-java . docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Java.Dockerfile -t id-configurator-java .
docker rmi id-configurator-java docker rmi id-configurator-java
[testenv:module-java-http]
package = skip
labels = end-to-end
change_dir = {tox_root}
dependency_groups = dev
docker =
java-repo
allowlist_externals =
docker
description =
Same as module-java, but against a plain-HTTP repository.
set_env =
JAVA_REPO_SCHEME = http
commands =
python3 -m id_tools test render-config {tox_root}/tests/configs/Java.yaml.j2 {env_dir}/configs/Java.yaml
docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Java.Dockerfile -t id-configurator-java-http .
docker rmi id-configurator-java-http
[docker:certificate-repo] [docker:certificate-repo]
dockerfile = {tox_root}/tests/dockerfiles/repos/certificate-repo.Dockerfile dockerfile = {tox_root}/tests/dockerfiles/repos/certificate-repo.Dockerfile
expose = expose =
@@ -251,6 +364,7 @@ commands =
dockerfile = {tox_root}/tests/dockerfiles/repos/php-repo.Dockerfile dockerfile = {tox_root}/tests/dockerfiles/repos/php-repo.Dockerfile
expose = expose =
PHP_REPO_PORT=8443/tcp PHP_REPO_PORT=8443/tcp
PHP_REPO_HTTP_PORT=8080/tcp
healthcheck_cmd = wget --no-check-certificate -qO- https://127.0.0.1:8443/packages.json || exit 1 healthcheck_cmd = wget --no-check-certificate -qO- https://127.0.0.1:8443/packages.json || exit 1
healthcheck_interval = 1 healthcheck_interval = 1
healthcheck_retries = 30 healthcheck_retries = 30
@@ -266,15 +380,37 @@ docker =
php-repo php-repo
allowlist_externals = allowlist_externals =
docker docker
set_env =
PHP_REPO_SCHEME = https
commands = commands =
python3 -m id_tools test render-config {tox_root}/tests/configs/Php.yaml.j2 {env_dir}/configs/Php.yaml python3 -m id_tools test render-config {tox_root}/tests/configs/Php.yaml.j2 {env_dir}/configs/Php.yaml
docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Php.Dockerfile -t id-configurator-php . docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Php.Dockerfile -t id-configurator-php .
docker rmi id-configurator-php docker rmi id-configurator-php
[testenv:module-php-http]
package = skip
labels = end-to-end
change_dir = {tox_root}
dependency_groups = dev
docker =
php-repo
allowlist_externals =
docker
description =
Same as module-php, but against a plain-HTTP repository, to verify
secure-http is disabled (and packagist.org too) for a non-HTTPS source.
set_env =
PHP_REPO_SCHEME = http
commands =
python3 -m id_tools test render-config {tox_root}/tests/configs/Php.yaml.j2 {env_dir}/configs/Php.yaml
docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Php.Dockerfile -t id-configurator-php-http .
docker rmi id-configurator-php-http
[docker:npm-repo] [docker:npm-repo]
dockerfile = {tox_root}/tests/dockerfiles/repos/npm-repo.Dockerfile dockerfile = {tox_root}/tests/dockerfiles/repos/npm-repo.Dockerfile
expose = expose =
NPM_REPO_PORT=8443/tcp NPM_REPO_PORT=8443/tcp
NPM_REPO_HTTP_PORT=8080/tcp
healthcheck_cmd = wget --no-check-certificate -qO- https://127.0.0.1:8443/idconfiguratortestpkg || exit 1 healthcheck_cmd = wget --no-check-certificate -qO- https://127.0.0.1:8443/idconfiguratortestpkg || exit 1
healthcheck_interval = 1 healthcheck_interval = 1
healthcheck_retries = 30 healthcheck_retries = 30
@@ -290,15 +426,36 @@ docker =
npm-repo npm-repo
allowlist_externals = allowlist_externals =
docker docker
set_env =
NPM_REPO_SCHEME = https
commands = commands =
python3 -m id_tools test render-config {tox_root}/tests/configs/Npm.yaml.j2 {env_dir}/configs/Npm.yaml python3 -m id_tools test render-config {tox_root}/tests/configs/Npm.yaml.j2 {env_dir}/configs/Npm.yaml
docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Npm.Dockerfile -t id-configurator-npm . docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Npm.Dockerfile -t id-configurator-npm .
docker rmi id-configurator-npm docker rmi id-configurator-npm
[testenv:module-npm-http]
package = skip
labels = end-to-end
change_dir = {tox_root}
dependency_groups = dev
docker =
npm-repo
allowlist_externals =
docker
description =
Same as module-npm, but against a plain-HTTP registry.
set_env =
NPM_REPO_SCHEME = http
commands =
python3 -m id_tools test render-config {tox_root}/tests/configs/Npm.yaml.j2 {env_dir}/configs/Npm.yaml
docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Npm.Dockerfile -t id-configurator-npm-http .
docker rmi id-configurator-npm-http
[docker:cargo-repo] [docker:cargo-repo]
dockerfile = {tox_root}/tests/dockerfiles/repos/cargo-repo.Dockerfile dockerfile = {tox_root}/tests/dockerfiles/repos/cargo-repo.Dockerfile
expose = expose =
CARGO_REPO_PORT=8443/tcp CARGO_REPO_PORT=8443/tcp
CARGO_REPO_HTTP_PORT=8080/tcp
healthcheck_cmd = wget --no-check-certificate -qO- https://127.0.0.1:8443/config.json || exit 1 healthcheck_cmd = wget --no-check-certificate -qO- https://127.0.0.1:8443/config.json || exit 1
healthcheck_interval = 1 healthcheck_interval = 1
healthcheck_retries = 30 healthcheck_retries = 30
@@ -314,15 +471,36 @@ docker =
cargo-repo cargo-repo
allowlist_externals = allowlist_externals =
docker docker
set_env =
CARGO_REPO_SCHEME = https
commands = commands =
python3 -m id_tools test render-config {tox_root}/tests/configs/Rust.yaml.j2 {env_dir}/configs/Rust.yaml python3 -m id_tools test render-config {tox_root}/tests/configs/Rust.yaml.j2 {env_dir}/configs/Rust.yaml
docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Rust.Dockerfile -t id-configurator-rust . docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Rust.Dockerfile -t id-configurator-rust .
docker rmi id-configurator-rust docker rmi id-configurator-rust
[testenv:module-rust-http]
package = skip
labels = end-to-end
change_dir = {tox_root}
dependency_groups = dev
docker =
cargo-repo
allowlist_externals =
docker
description =
Same as module-rust, but against a plain-HTTP sparse registry.
set_env =
CARGO_REPO_SCHEME = http
commands =
python3 -m id_tools test render-config {tox_root}/tests/configs/Rust.yaml.j2 {env_dir}/configs/Rust.yaml
docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Rust.Dockerfile -t id-configurator-rust-http .
docker rmi id-configurator-rust-http
[docker:go-repo] [docker:go-repo]
dockerfile = {tox_root}/tests/dockerfiles/repos/go-repo.Dockerfile dockerfile = {tox_root}/tests/dockerfiles/repos/go-repo.Dockerfile
expose = expose =
GO_REPO_PORT=8443/tcp GO_REPO_PORT=8443/tcp
GO_REPO_HTTP_PORT=8080/tcp
healthcheck_cmd = wget --no-check-certificate -qO- https://127.0.0.1:8443/example.invalid/idconfiguratortestpkg/@v/list || exit 1 healthcheck_cmd = wget --no-check-certificate -qO- https://127.0.0.1:8443/example.invalid/idconfiguratortestpkg/@v/list || exit 1
healthcheck_interval = 1 healthcheck_interval = 1
healthcheck_retries = 30 healthcheck_retries = 30
@@ -338,15 +516,37 @@ docker =
go-repo go-repo
allowlist_externals = allowlist_externals =
docker docker
set_env =
GO_REPO_SCHEME = https
commands = commands =
python3 -m id_tools test render-config {tox_root}/tests/configs/Go.yaml.j2 {env_dir}/configs/Go.yaml python3 -m id_tools test render-config {tox_root}/tests/configs/Go.yaml.j2 {env_dir}/configs/Go.yaml
docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Go.Dockerfile -t id-configurator-go . docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Go.Dockerfile -t id-configurator-go .
docker rmi id-configurator-go docker rmi id-configurator-go
[testenv:module-go-http]
package = skip
labels = end-to-end
change_dir = {tox_root}
dependency_groups = dev
docker =
go-repo
allowlist_externals =
docker
description =
Same as module-go, but against a plain-HTTP module proxy, to verify
GOINSECURE is configured correctly for a non-HTTPS GOPROXY.
set_env =
GO_REPO_SCHEME = http
commands =
python3 -m id_tools test render-config {tox_root}/tests/configs/Go.yaml.j2 {env_dir}/configs/Go.yaml
docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Go.Dockerfile -t id-configurator-go-http .
docker rmi id-configurator-go-http
[docker:ruby-repo] [docker:ruby-repo]
dockerfile = {tox_root}/tests/dockerfiles/repos/ruby-repo.Dockerfile dockerfile = {tox_root}/tests/dockerfiles/repos/ruby-repo.Dockerfile
expose = expose =
RUBY_REPO_PORT=8443/tcp RUBY_REPO_PORT=8443/tcp
RUBY_REPO_HTTP_PORT=8080/tcp
healthcheck_cmd = wget --no-check-certificate -qO- https://127.0.0.1:8443/versions || exit 1 healthcheck_cmd = wget --no-check-certificate -qO- https://127.0.0.1:8443/versions || exit 1
healthcheck_interval = 1 healthcheck_interval = 1
healthcheck_retries = 30 healthcheck_retries = 30
@@ -362,15 +562,36 @@ docker =
ruby-repo ruby-repo
allowlist_externals = allowlist_externals =
docker docker
set_env =
RUBY_REPO_SCHEME = https
commands = commands =
python3 -m id_tools test render-config {tox_root}/tests/configs/Ruby.yaml.j2 {env_dir}/configs/Ruby.yaml python3 -m id_tools test render-config {tox_root}/tests/configs/Ruby.yaml.j2 {env_dir}/configs/Ruby.yaml
docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Ruby.Dockerfile -t id-configurator-ruby . docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Ruby.Dockerfile -t id-configurator-ruby .
docker rmi id-configurator-ruby docker rmi id-configurator-ruby
[testenv:module-ruby-http]
package = skip
labels = end-to-end
change_dir = {tox_root}
dependency_groups = dev
docker =
ruby-repo
allowlist_externals =
docker
description =
Same as module-ruby, but against a plain-HTTP gem source.
set_env =
RUBY_REPO_SCHEME = http
commands =
python3 -m id_tools test render-config {tox_root}/tests/configs/Ruby.yaml.j2 {env_dir}/configs/Ruby.yaml
docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/Ruby.Dockerfile -t id-configurator-ruby-http .
docker rmi id-configurator-ruby-http
[docker:nuget-repo] [docker:nuget-repo]
dockerfile = {tox_root}/tests/dockerfiles/repos/nuget-repo.Dockerfile dockerfile = {tox_root}/tests/dockerfiles/repos/nuget-repo.Dockerfile
expose = expose =
NUGET_REPO_PORT=8443/tcp NUGET_REPO_PORT=8443/tcp
NUGET_REPO_HTTP_PORT=8080/tcp
healthcheck_cmd = wget --no-check-certificate -qO- https://127.0.0.1:8443/index.json || exit 1 healthcheck_cmd = wget --no-check-certificate -qO- https://127.0.0.1:8443/index.json || exit 1
healthcheck_interval = 1 healthcheck_interval = 1
healthcheck_retries = 30 healthcheck_retries = 30
@@ -386,11 +607,32 @@ docker =
nuget-repo nuget-repo
allowlist_externals = allowlist_externals =
docker docker
set_env =
NUGET_REPO_SCHEME = https
commands = commands =
python3 -m id_tools test render-config {tox_root}/tests/configs/NuGet.yaml.j2 {env_dir}/configs/NuGet.yaml python3 -m id_tools test render-config {tox_root}/tests/configs/NuGet.yaml.j2 {env_dir}/configs/NuGet.yaml
docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/NuGet.Dockerfile -t id-configurator-nuget . docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/NuGet.Dockerfile -t id-configurator-nuget .
docker rmi id-configurator-nuget docker rmi id-configurator-nuget
[testenv:module-nuget-http]
package = skip
labels = end-to-end
change_dir = {tox_root}
dependency_groups = dev
docker =
nuget-repo
allowlist_externals =
docker
description =
Same as module-nuget, but against a plain-HTTP feed, to verify
allowInsecureConnections is configured correctly for a non-HTTPS source.
set_env =
NUGET_REPO_SCHEME = http
commands =
python3 -m id_tools test render-config {tox_root}/tests/configs/NuGet.yaml.j2 {env_dir}/configs/NuGet.yaml
docker buildx build --platform linux/amd64 --add-host=host.docker.internal:host-gateway --build-context generated-config={env_dir}/configs -f {tox_root}/tests/dockerfiles/NuGet.Dockerfile -t id-configurator-nuget-http .
docker rmi id-configurator-nuget-http
[docker:config-url-repo] [docker:config-url-repo]
dockerfile = {tox_root}/tests/dockerfiles/repos/config-url-repo.Dockerfile dockerfile = {tox_root}/tests/dockerfiles/repos/config-url-repo.Dockerfile
expose = expose =
Generated
+1 -1
View File
@@ -424,7 +424,7 @@ dependencies = [
] ]
name = "id-configurator" name = "id-configurator"
source = {editable = "."} source = {editable = "."}
version = "2026.10.5" version = "2026.10.6"
[package.dev-dependencies] [package.dev-dependencies]
dev = [ dev = [