Merge pull request #12 from d9pouces/dev

Dev
This commit is contained in:
d9pouces
2026-10-07 07:44:10 +02:00
committed by GitHub
35 changed files with 559 additions and 70 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)
+22 -5
View File
@@ -28,9 +28,20 @@ tool targets Docker images, which are built and run as root:
- Ivy: `~/.ivy2/ivysettings.xml`, as a chain of `ibiblio` resolvers. - Ivy: `~/.ivy2/ivysettings.xml`, as a chain of `ibiblio` resolvers.
- SBT: `~/.sbt/repositories`, the resolver override file SBT reads for its - SBT: `~/.sbt/repositories`, the resolver override file SBT reads for its
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. A repository
whose URL isn't HTTPS gets `, allowInsecureProtocol` appended to its
line - SBT's Coursier-backed resolver otherwise refuses it outright
("insecure protocol is unsupported"), unlike every other entry in
`~/.sbt/repositories` which takes no such suffix.
- 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") - its
standalone `lein` launcher (`leiningen.core.main/-main`) unconditionally
registers an aborting wagon for the "http" scheme before even reading the
project/profile config, so there is no project.clj/profiles.clj setting
(there is no `:insecure` key anywhere in Leiningen's own source) that
can work around this: a non-HTTPS repository configured here will not be
usable from Leiningen specifically, regardless of what this module does.
""" """
from __future__ import annotations from __future__ import annotations
@@ -39,6 +50,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
@@ -233,13 +245,18 @@ def _write_ivy_settings(context: Context, repositories: list[JavaRepository]) ->
logger.info("configured ivy to use %d repositories", len(repositories)) logger.info("configured ivy to use %d repositories", len(repositories))
def _sbt_repository_line(repository: JavaRepository) -> str:
line = f" {repository.name}: {repository.url}"
if urlparse(repository.url).scheme.lower() != "https":
line += ", allowInsecureProtocol"
return line
def _write_sbt_repositories( def _write_sbt_repositories(
context: Context, repositories: list[JavaRepository] context: Context, repositories: list[JavaRepository]
) -> None: ) -> None:
lines = ["[repositories]", " local"] lines = ["[repositories]", " local"]
lines.extend( lines.extend(_sbt_repository_line(repository) for repository in repositories)
f" {repository.name}: {repository.url}" for repository in repositories
)
context.write_file(_SBT_REPOSITORIES, ("\n".join(lines) + "\n").encode("utf-8")) context.write_file(_SBT_REPOSITORIES, ("\n".join(lines) + "\n").encode("utf-8"))
logger.info("configured sbt to use %d repositories", len(repositories)) logger.info("configured sbt to use %d repositories", len(repositories))
+4 -3
View File
@@ -29,7 +29,7 @@ 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__)
@@ -83,10 +83,11 @@ def _write_poetry_config(
) -> None: ) -> None:
lines = [] lines = []
for repository in repositories: for repository in repositories:
lines.append(f"[repositories.{repository.name}]") name = sanitize_repository_name(repository.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("")
lines.append(f"[certificates.{repository.name}]") lines.append(f"[certificates.{name}]")
lines.append(f"cert = {_toml_string(_CA_BUNDLE)}") lines.append(f"cert = {_toml_string(_CA_BUNDLE)}")
lines.append("") lines.append("")
content = ("\n".join(lines).rstrip() + "\n").encode("utf-8") content = ("\n".join(lines).rstrip() + "\n").encode("utf-8")
+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}",
+1 -1
View File
@@ -44,7 +44,7 @@ maintainers = [
name = "id-configurator" name = "id-configurator"
readme = "README.md" readme = "README.md"
requires-python = ">=3.13" requires-python = ">=3.13"
version = "2026.10.5" version = "2026.10.6"
[project.scripts] [project.scripts]
id-configurator = "id_configurator:main" id-configurator = "id_configurator:main"
+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:
+13 -1
View File
@@ -4,6 +4,7 @@ COPY --from=target / /src/
COPY --from=generated-config Java.yaml /config.yaml COPY --from=generated-config Java.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 JAVA_REPO_SCHEME
# Every build tool the `java` module configures: Maven itself (already part # Every build tool the `java` module configures: Maven itself (already part
# of this image), Gradle, Ivy and Leiningen (all packaged for this Ubuntu # of this image), Gradle, Ivy and Leiningen (all packaged for this Ubuntu
# base), and SBT (no package available, fetched as a plain release tarball). # base), and SBT (no package available, fetched as a plain release tarball).
@@ -43,12 +44,23 @@ RUN java -jar /usr/share/java/ivy.jar -settings /root/.ivy2/ivysettings.xml \
-retrieve "/tmp/ivyretrieve/[artifact]-[revision].[ext]" \ -retrieve "/tmp/ivyretrieve/[artifact]-[revision].[ext]" \
&& test -f /tmp/ivyretrieve/idconfiguratortestpkg-0.0.1.jar && test -f /tmp/ivyretrieve/idconfiguratortestpkg-0.0.1.jar
# Leiningen's standalone launcher unconditionally refuses any plain-HTTP
# repository ("Tried to use insecure HTTP repository without TLS") before
# even reading project.clj/profiles.clj - there is no `:insecure` key or
# other configuration escape hatch for this (confirmed from Leiningen's own
# source: leiningen.core.main/-main registers an aborting wagon for the
# "http" scheme unconditionally). So this check is skipped for the
# module-java-http variant: no id-configurator config could make it pass.
RUN mkdir -p /tmp/leintest && cd /tmp/leintest \ RUN mkdir -p /tmp/leintest && cd /tmp/leintest \
&& cat > project.clj <<'EOF' && cat > project.clj <<'EOF'
(defproject leintest "0.1.0" (defproject leintest "0.1.0"
:dependencies [[org.interdiode/idconfiguratortestpkg "0.0.1"]]) :dependencies [[org.interdiode/idconfiguratortestpkg "0.0.1"]])
EOF EOF
RUN cd /tmp/leintest && lein deps :tree | grep -q idconfiguratortestpkg RUN if [ "$JAVA_REPO_SCHEME" = "https" ]; then \
cd /tmp/leintest && lein deps :tree | grep -q idconfiguratortestpkg; \
else \
echo "skipping leiningen: it cannot use a non-HTTPS repository"; \
fi
RUN mkdir -p /tmp/sbttest/project \ RUN mkdir -p /tmp/sbttest/project \
&& cat > /tmp/sbttest/build.sbt <<'EOF' && cat > /tmp/sbttest/build.sbt <<'EOF'
+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;
}
+25
View File
@@ -339,6 +339,31 @@ def test_apply_writes_sbt_repositories(tmp_path) -> None:
) )
def test_apply_marks_non_https_sbt_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)
repositories = (dst / "root/.sbt/repositories").read_text(encoding="utf-8")
assert repositories == (
"[repositories]\n"
" local\n"
" interdiode: http://example.invalid/maven, allowInsecureProtocol\n"
)
def test_apply_writes_lein_profiles(tmp_path) -> None: def test_apply_writes_lein_profiles(tmp_path) -> None:
dst = tmp_path / "dst" dst = tmp_path / "dst"
context = Context(config=make_config(TWO_REPOS_CONFIG), dst=dst, src=None) context = Context(config=make_config(TWO_REPOS_CONFIG), dst=dst, src=None)
+35
View File
@@ -183,6 +183,41 @@ def test_apply_multiple_repositories(tmp_path) -> None:
) )
def test_apply_sanitizes_poetry_repository_name_with_special_characters(
tmp_path,
) -> None:
data = {
"uuid": "12345678-1234-5678-1234-567812345678",
"organisation": "InterDiode",
"configurations": {
"python": {
"repositories": [
{
"name": "weird.name]here[bad",
"index-url": "https://example.invalid/simple",
}
]
}
},
}
config = Configuration.model_validate(data)
dst = tmp_path / "dst"
context = Context(config=config, dst=dst, src=None)
PythonModule().apply(context)
poetry_config = (dst / "root/.config/pypoetry/config.toml").read_text(
encoding="utf-8"
)
assert poetry_config == (
"[repositories.weird_name_here_bad]\n"
'url = "https://example.invalid/simple"\n'
"\n"
"[certificates.weird_name_here_bad]\n"
'cert = "/etc/ssl/certs/ca-certificates.crt"\n'
)
def test_apply_writes_poetry_config_for_each_configured_user(tmp_path) -> None: def test_apply_writes_poetry_config_for_each_configured_user(tmp_path) -> None:
config = Configuration.model_validate(ONE_REPO_CONFIG) config = Configuration.model_validate(ONE_REPO_CONFIG)
dst = tmp_path / "dst" dst = tmp_path / "dst"
+248 -4
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,33 @@ 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-arg JAVA_REPO_SCHEME={env:JAVA_REPO_SCHEME} --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. Leiningen is
skipped here (see Java.Dockerfile): it refuses any non-HTTPS repository
unconditionally, with no configuration able to change that.
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-arg JAVA_REPO_SCHEME={env:JAVA_REPO_SCHEME} --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 +366,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 +382,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 +428,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 +473,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 +518,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 +564,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 +609,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 = [